package libnet

import (
	"fmt"
	"gamesdk/common/libnet/cli"
	"gamesdk/common/libnet/inter"
	"gamesdk/common/log"
	"gamesdk/common/recover"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

type Accept func(cli *cli.Client)

type Server struct {
	port      int
	server    inter.Server
	count     int32
	maxConn   int32
	heartbeat int
	clients   sync.Map
	upgrader  websocket.Upgrader
	waitGroup sync.WaitGroup
}

/*
*初始化服务
*参数说明:
*@param:port	 	端口号
*@param:maxConn     最大的连接数
*@param:heartbeat   心跳时间，单位秒 小于0为无心跳
*@param:accept   	建立链接回调函数
 */
func NewServer(port int, maxConn int32, heartbeat int, server inter.Server) *Server {
	return &Server{
		port:      port,
		server:    server,
		count:     0,
		maxConn:   maxConn,
		heartbeat: heartbeat,
		upgrader:  websocket.Upgrader{},
	}
}

func (this *Server) GetOnlineNum() int32 {
	return atomic.LoadInt32(&this.count)
}

func (this *Server) GetMax() int32 {
	return this.maxConn
}

func (this *Server) Run() {
	log.Info("Websocket Start Listen %d", this.port)
	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP)

	this.upgrader = websocket.Upgrader{
		// 解决跨域问题
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}

	go func(srv *Server) {

		gin.SetMode(gin.ReleaseMode)
		router := gin.Default()
		router.GET("/", srv.funcConnect)
		router.GET("/keeplive", srv.funcKeepLive)
		err := router.Run(fmt.Sprintf(":%d", this.port))
		if err != nil {
			panic(err)
		}

		// http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// 	srv.funcAccept(w, r)
		// })
		// err := http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", this.port), nil)
		// if err != nil {
		// 	panic(err)
		// }
	}(this)

	this.funcExit(c)
}

/*
*建立连接
 */
func (this *Server) funcConnect(c *gin.Context) {
	defer recover_handle.RecoverHandle("funcConnect")
	r := c.Request
	w := c.Writer
	r.Header.Del("Origin")
	r.ParseForm()
	token := c.Query("token")
	if len(token) <= 0 {
		log.Debug("token is nil")
		return
	}
	//log.Debug("token:%s", token)

	this.waitGroup.Add(1)
	defer this.waitGroup.Done()
	atomic.AddInt32(&this.count, 1)
	if atomic.LoadInt32(&this.count) > int32(this.maxConn) {
		atomic.AddInt32(&this.count, -1)
		return
	}
	conn, err := this.upgrader.Upgrade(w, r, nil)
	if err != nil {
		//log.Error(err.Error())
		atomic.AddInt32(&this.count, -1)
		return
	}
	ip := c.ClientIP()
	cli := cli.NewClient(conn, ip, this.heartbeat)
	this.server.Accept(cli)
	conn.Close()
	atomic.AddInt32(&this.count, -1)
	//log.Debug("token:%s exit", token)
	return
}

func (this *Server) funcExit(m chan os.Signal) {
	log.Debug("wait exit")
	<-m
	log.Debug("start exit")
	this.server.Exit()
	this.waitGroup.Wait()
	//log.Info("server exit")
}

func (this *Server) funcKeepLive(c *gin.Context) {
	defer recover_handle.RecoverHandle("funcKeepLive")
	c.JSON(http.StatusOK, gin.H{
		"Body": "success",
		"Time": time.Now().Unix(),
	})
}
